package com.gxycoding.websocket.config;

import com.gxycoding.websocket.common.ConstantUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;

import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Description(webSocket 服务)
 * author: Gao xueyong
 * Create at: 2020/7/15 8:36 下午
 */
@Slf4j
@Component
@ServerEndpoint(value = "/websocket/server/{userId}/{password}",configurator = GetHttpSessionConfigurator.class)
public class WebSocketServer {
    // 在线人数
    private static int onlineCount = 0;
    // 在线人员注册 一个用户可以多浏览器登录
    private static ConcurrentHashMap<String, Map<String,WebSocketServer>> webSocketSet = new ConcurrentHashMap<>();
    // 在线管理员注册 一个用户可以多浏览器登录
    private static ConcurrentHashMap<String, Map<String,WebSocketServer>> adminWebSocketSet = new ConcurrentHashMap<>();
    //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;
    private HttpSession httpSession;
    // 用户标识
    private String userIdUUid = "";

    /**
     * 打开连接回调方法
     * @param userId 用户ID
     * @param password 密码
     * @param session 客户端session
     */
    @OnOpen
    public void onOpen(@PathParam(value = "userId") String userId, @PathParam("password") String password, Session session) {

        this.session = session;
        this.userIdUUid = getUserIdUUid(userId, password);
        String ip = (String) session.getUserProperties().get(ConstantUtil.clinetIp);
        Map<String, WebSocketServer> map = webSocketSet.get(userId);
        map = null == map ? new HashMap<String, WebSocketServer>() : map;
        map.put(ip,this);
        webSocketSet.put(userIdUUid,map);

        //在线数加1
        addOnlineCount();
        log.info("有一连接关闭！当前在线人数为" + getOnlineCount());
    }

    /**
     * 关闭连接回调方法
     * @param userId 用户ID
     * @param password 密码
     */
    @OnClose
    public void onClose(@PathParam(value = "userId") String userId, @PathParam("password") String password) {
        Map<String, WebSocketServer> map = webSocketSet.get(getUserIdUUid(userId,password));
        String ip = (String)httpSession.getAttribute(ConstantUtil.clinetIp);
        if (null != map && null != map.get(ip)){
            map.remove(ip);
        }
        subOnlineCount();           //在线数减1
        log.info("有一连接关闭！当前在线人数为" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     * @param message 客户端发送过来的消息*/
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("来自客户端的消息:" + message);
        //可以自己约定字符串内容，比如 内容|0 表示信息群发，内容|X 表示信息发给id为X的用户
        try {
            sendtoAll(message);
        } catch (IOException e) {
            log.error("收取信息发生错误",e);
        }
    }

    /**
     * 发生错误回调方法
     * @param session 连接会话
     * @param error 错误
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误",error);
    }


    /**
     * 发送信息
     * @param message 消息
     * @throws IOException 异常
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    /**
     * 发送信息给指定ID用户，如果用户不在线则返回不在线信息给自己
     * @param message 消息
     * @param sendUserId 用户ID
     * @throws IOException 异常
     */
    public void sendToUser(String message,String sendUserId) throws IOException {
        if (webSocketSet.get(sendUserId) != null) {
            Map<String, WebSocketServer> map = webSocketSet.get(sendUserId);
            for (WebSocketServer wss : map.values()) {
                wss.sendMessage(message);
            }
        }
    }

    /**
     * 发送信息给所有人
     * @param message 消息
     * @throws IOException 异常
     */
    public void sendtoAll(String message) throws IOException {
        for (Map<String,WebSocketServer> map : webSocketSet.values()) {
            for (WebSocketServer wss : map.values()){
                wss.sendMessage(message);
            }
        }
    }

    public Map<String,String> getOnlineUsers(){
        Map<String,String> userinfoMap = new HashMap<>();
        webSocketSet.keySet().stream().forEach(x-> userinfoMap.put(x,x));
        return userinfoMap;
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

    private String getUserIdUUid(String userId,String passowrd){
        return userId+"-"+ DigestUtils.md5DigestAsHex(passowrd.getBytes());
    }

}
